/**
 * 
 */
package hichecker.ui.custom_views.conflict_handling;

import hichecker.university.Course;
import hichecker.university.Series;
import hichecker.university.Student;
import hichecker.university.Task;

import java.util.List;

/**
 *
 */
public class ConflictImportedTableModel extends ConflictOpenedTableModel {

	private List<Student> oldStudents;
	private Series oldSeries;
	private int[] manuallySet;
	
	public enum ConflictType {NEW, OVERWRITING, NONE}
	
	public ConflictImportedTableModel(Course oldCourse, Course newCourse, List<Student> allStudents) {
		super(newCourse.getParticipants(), newCourse.getTheOnlySeries(), allStudents);
		this.oldSeries = oldCourse.getSeriesByID(series.getID());
		this.oldStudents = oldCourse.getParticipants();
		this.manuallySet = new int[getRowCount()];
		
		manuallySet = new int[getRowCount()];
	}
	
	@Override
	public String getColumnName(int column) {
		if (column == 0) return "<<";
		return super.getColumnName(column - 1);
	}

	@Override
	protected String getRowID(int row) {
		return allStudents.size() <= row ? null : "" + allStudents.get(row).getID();
	}

	@Override
	public Object getValueAt(int row, int column) {
		// Out of range
		if (row >= getRowCount() || column >= getColumnCount())
			return null;
		
		// If it's not the fist column, handle like super class
		if (column != 0)
			return super.getValueAt(row, column - 1);
		
		
		// If the row was manually set get the manually result
		if (manuallySet != null) {
			switch (manuallySet[row]) {
				case 1: return true;
				case 2: return false;
			}
		}

		// The row was not manually set, so get the conflict type of each column of the row
		for (int i = 1; i < getColumnCount(); i++) 
			if (getCellConflictType(row, i) == ConflictType.OVERWRITING) return false;
		return true;
	}

	@Override
	public boolean isCellEditable(int row, int column) {
		return column == 0;
	}
	
	@Override
	public void setValueAt(Object aValue, int row, int column) {
		if (column != 0) return;
			manuallySet[row] = Boolean.parseBoolean("" + aValue) == true ? 1 : 2;
	}
	
	@Override
	public int getColumnCount() {
		return super.getColumnCount() + 1;
	}
	
	@Override
	public Class<?> getColumnClass(int column) {
		switch (column) {
			case 0: return Boolean.class;
			default: return ConflictType.class;
		}
	}
	
	
	public ConflictType getCellConflictType(int row, int column) {
		// First column can cause a conflict
		if (column == 0) return ConflictType.NONE;
		
		column -= 1;
		
		// Try to get the old and new student indexes
		Student selStudent = allStudents.get(row);
		int oldStudentIndex = oldStudents.indexOf(selStudent);
		int newStudentIndex = students.indexOf(selStudent); 

		// There's no new student, so nothing changes => no conflict
		if (newStudentIndex == -1)
			return ConflictType.NONE;
		
		// There's no old student, so it's a new value => no conflict
		if (oldStudentIndex == -1)
			return ConflictType.NEW;

		// Get the old and new student
		Student oldStudent = oldStudents.get(oldStudentIndex);
		Student newStudent = students.get(newStudentIndex);
		
		// The column is a student data related column
		if (column < FIXED_COLUMNS) {
			return checkStudentData(oldStudent, newStudent, column);
		}
		// The column is a points data related column
		else {
			return checkStudentPoints(oldSeries, series, selStudent, column - FIXED_COLUMNS);
		}
		
	}
	/**
	 * Indicates whether the changes for the referenced student can be saved
	 * 
	 * @param student
	 * @return
	 */
	public boolean changesConfirmed(Student student) {
		int index = allStudents.indexOf(student);
		return index == -1 ? false : Boolean.parseBoolean("" + getValueAt(index, 0));
	}
	
	private ConflictType checkStudentData(Student oldStudent, Student newStudent, int valueNumber) {
		// No old value
		if (oldStudent == null) {
			return newStudent == null ? ConflictType.NONE: ConflictType.NEW;
		}
		
		// No new value
		if (newStudent == null) {
			return ConflictType.NONE;
		}

		// Get the old and new value depending on the parameter valueNumber
		String oldValue = null;
		String newValue = null;
		switch (valueNumber) {
		case 0:
			oldValue = oldStudent.getLastName();
			newValue = newStudent.getLastName();
			break;
		case 1:
			oldValue = oldStudent.getFirstName();
			newValue = newStudent.getFirstName();
			break;
		case 2:
			oldValue = oldStudent.getMatrikel();
			newValue = newStudent.getMatrikel();
			break;
		case 3:
			oldValue = oldStudent.getStudyCourse();
			newValue = newStudent.getStudyCourse();
			break;
		}
		
		// Check gathered values on changes
		if (oldValue != null && oldValue.trim().length() > 0)
			return oldValue.equals(newValue) ? ConflictType.NONE : ConflictType.OVERWRITING;
		return newValue != null && newValue.trim().length() > 0 ? ConflictType.NEW : ConflictType.NONE;
	}
	
	
	private ConflictType checkStudentPoints(Series oldSeries, Series newSeries, Student student, int taskAt) {
		// No old value
		if (oldSeries == null)
			return newSeries == null ? ConflictType.NONE : ConflictType.NEW;
		
		// No new value
		if (newSeries == null)
			return ConflictType.NONE;
		
		// Get the different tasks
		Task oldTask = oldSeries.getTaskAt(taskAt);
		Task newTask = newSeries.getTaskAt(taskAt);
		if (oldTask == null || newTask == null)
			return ConflictType.NONE;
		
		// No points exist for this student
		if (oldTask.getGainedPoints(student) == -1) {
			if (newTask.getGainedPoints(student) == -1) return ConflictType.NONE;
			return ConflictType.NEW;
		}
		
		// Points exist for this student
		if (!(newTask.getGainedPoints(student) == oldTask.getGainedPoints(student)))
			return ConflictType.OVERWRITING;
		
		return ConflictType.NONE;
	}
	
	@Override
	public Object[] getHeaderValues() {
		Object[] tmpHeaderValues = super.getHeaderValues();
		
		headerValues = new Object[getColumnCount()];
		// The header for the checkboxes
		headerValues[0] = "<html><br>&lt&lt</html>";
		
		for (int i = 1; i < getColumnCount(); i++) {
			headerValues[i] = tmpHeaderValues[i-1];
		}
		
		return headerValues;
	}

}

